﻿/*
    Copyright (C) 2012  Milton da Silva Junior - admin.jr.dotnet@gmail.com

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Loja.Data;
using Loja.DataDTO;
using Loja.Business.Validacao.Produto;


namespace Loja.Business
{
    public class ProdutoBLL
    {
        private RepositoryFactory<Produto> reposistoryFactory;
        private IRepository<Produto> produtoRepository;

        public ProdutoBLL()
        {
            reposistoryFactory = new RepositoryFactory<Produto>();
            produtoRepository = reposistoryFactory.CriarRepositorioDados();
        }

        public ProdutoBLL(bool lazyLoadingEnabled)
        {
            reposistoryFactory = new RepositoryFactory<Produto>();
            produtoRepository = reposistoryFactory.CriarRepositorioDados(new LojaEntities(), lazyLoadingEnabled);
        }

        ~ProdutoBLL()
        {
            if (produtoRepository != null)
                produtoRepository.Dispose();
        }

        public void Salvar(ProdutoDTO produtoDTO, IList<EstoqueDTO> listaEstoqueDTO)
        {
            produtoRepository.Add(GetProduto(produtoDTO, listaEstoqueDTO));
            produtoRepository.SaveChanges();
        }

        public void Atualizar(ProdutoDTO produtoDTO, IList<EstoqueDTO> listaEstoque)
        {
            ProdutoBLL produtoBll = new ProdutoBLL();
            var produtoDb = produtoRepository.Single(p => p.IdProduto == produtoDTO.Id);

            produtoDb.Descricao = produtoDTO.Descricao;
            produtoDb.IdCategoria = produtoDTO.IdCategoria;
            produtoDb.Codigo = produtoDTO.Codigo;
            produtoDb.IdFornecedor = produtoDTO.IdFornecedr;
            produtoDb.PrecoCusto = produtoDTO.PrecoCusto;
            produtoDb.Percentual = produtoDTO.Precentual;
            produtoDb.IdMarca = produtoDTO.IdMarca;
            produtoDb.Tags = produtoDTO.Tags;

            EstoqueBLL estoqueBll = new EstoqueBLL();
 
            foreach (var item in listaEstoque)
            {
                if (produtoDb.Estoque.Count(o => o.Tamanho == item.Tamanho) > 0)
                {
                    produtoDb.Estoque.Single(o => o.Tamanho == item.Tamanho).Quantidade = item.Quantidade;
                }
                else
                {
                    produtoDb.Estoque.Add(new Estoque { DataCadastro = DateTime.Now, Quantidade = item.Quantidade, Tamanho = item.Tamanho });
                }
            }
            produtoRepository.SaveChanges();
        }

        public List<Produto> GetListaProduto(int page, int rp, ref int total)
        {
            var resutado = produtoRepository.GetAll();
            total = resutado.Count();
            return produtoRepository.GetAll().ToList().Skip((page - 1) * rp).Take(rp).ToList();
        }

        public ProdutoDTO GetProdutoById(int id)
        {
            var produto = produtoRepository.Single(p => p.IdProduto == id);

            var produtoDTO = new ProdutoDTO
            {
                Id = produto.IdProduto,
                Codigo = produto.Codigo,
                Descricao = produto.Descricao,
                IdCategoria = produto.IdCategoria,
                IdFornecedr = produto.IdFornecedor,
                IdMarca = produto.IdMarca,
                Precentual = produto.Percentual,
                PrecoCusto = produto.PrecoCusto,
                Tags = produto.Tags
            };
            return produtoDTO;
        }

        public string GerarCodigo(int? idProduto)
        {
            int idUltimoProduto = 0;

            if (idProduto != null)
                idUltimoProduto = (int)idProduto;
            else
            {
                int quantidade = produtoRepository.GetAll().Count();
                if (quantidade == 0)
                    idProduto = 1;
                else
                    idUltimoProduto = produtoRepository.GetAll().Max(p => p.IdProduto);
            }

            string codigo = string.Format("{0:00000000}", idUltimoProduto);
            return codigo;
        }

        private List<Produto> Pesquisar(int coluna, string pesquisa, int page, int rp, ref int total)
        {
            IRepositoryFactory<Categoria> categoryRepositoryFactory;
            IRepositoryFactory<Fornecedor> fornecedorRepositoryFactory;
            IRepositoryFactory<Marca> marcaRepositoryFactory;

            switch (coluna)
            {
                case 1:
                    var resultCodigo = produtoRepository.Find(o => o.Codigo == pesquisa);
                    total = resultCodigo.Count();
                    return resultCodigo.ToList().Skip((page - 1) * rp).Take(rp).ToList();
                case 2:
                    categoryRepositoryFactory = new RepositoryFactory<Categoria>();
                    IRepository<Categoria> cr = categoryRepositoryFactory.CriarRepositorioDados();
                    var resultCateogoria = from p in produtoRepository.GetAll()
                                           from c in cr.GetAll()
                                           where p.IdCategoria == c.IdCategoria && c.IdPai == null && c.Descricao.StartsWith(pesquisa)
                                               select p;
                    total = resultCateogoria.Count();
                    return resultCateogoria.ToList().Skip((page - 1) * rp).Take(rp).ToList();
                case 3:
                    categoryRepositoryFactory = new RepositoryFactory<Categoria>();
                    IRepository<Categoria> crs = categoryRepositoryFactory.CriarRepositorioDados();

                    var resultSubcateogoria = from p in produtoRepository.GetAll()
                                           from c in crs.GetAll()
                                           where p.IdCategoria == c.IdCategoria && c.IdPai != null && c.Descricao.ToLower().StartsWith(pesquisa.ToLower())
                                           select p;
                    total = resultSubcateogoria.Count();
                    return resultSubcateogoria.ToList().Skip((page - 1) * rp).Take(rp).ToList();
                case 4:
                    fornecedorRepositoryFactory = new RepositoryFactory<Fornecedor>();
                    IRepository<Fornecedor> fornecedorRepository = fornecedorRepositoryFactory.CriarRepositorioDados();

                    var resultFornecedor = from p in produtoRepository.GetAll()
                                           from f in fornecedorRepository.GetAll()
                                           where p.IdFornecedor == f.IdFornecedor && f.Nome.ToLower().StartsWith(pesquisa.ToLower())
                                               select p;
                    total = resultFornecedor.Count();
                    return resultFornecedor.Skip((page - 1) * rp).Take(rp).ToList();
                case 5:
                    marcaRepositoryFactory = new RepositoryFactory<Marca>();
                    IRepository<Marca> marcaRepository = marcaRepositoryFactory.CriarRepositorioDados();

                    var resultMarca = from p in produtoRepository.GetAll()
                                      from m in marcaRepository.GetAll()
                                      where p.IdMarca == m.IdMarca && m.Nome.ToLower().StartsWith(pesquisa.ToLower())
                                          select p;
                    total = resultMarca.Count();
                    return resultMarca.Skip((page - 1) * rp).Take(rp).ToList();
            }
            return null;
        }

        public string Validar(ProdutoDTO produto)
        {
            IList<IValida> validacoes = new List<IValida>();

            validacoes.Add(new ValidaCategoriaObrigatoria());
            validacoes.Add(new ValidaCodigoObrigatorio());
            validacoes.Add(new ValidaDescricaoObrigatoria());
            validacoes.Add(new ValidaFornecedorObrigatorio());
            validacoes.Add(new ValidaMarcaObrigatoria());
            validacoes.Add(new ValidaPercentualObrigatorio());
            validacoes.Add(new ValidaPrecoCustoObrigatorio());

            var valida = new ValidaProduto();
            valida.Validar(produto, validacoes);

            return valida.Erros.ToString().Trim();
        }

        private Produto GetProduto(ProdutoDTO produto, IList<EstoqueDTO> listaEstoque)
        {
            var prod = new Produto
            {
                Descricao = produto.Descricao,
                IdCategoria = produto.IdCategoria,
                Codigo = produto.Codigo,
                DataCadastro = produto.DataCadastro,
                IdFornecedor = produto.IdFornecedr,
                PrecoCusto = produto.PrecoCusto,
                Percentual = produto.Precentual,
                IdMarca = produto.IdMarca,
                Tags = produto.Tags
            };

            if (produto.Id > 0)
            {
                prod.IdProduto = produto.Id;
            }

            foreach (var item in listaEstoque)
            {
                prod.Estoque.Add(new Estoque
                {
                    IdProduto = prod.IdProduto,
                    Quantidade = item.Quantidade,
                    Tamanho = item.Tamanho,
                    DataCadastro = item.DataCadastro
                });
            }
            return prod;
        }

        public List<ProdutoDTO> GetListaProdutoDTO(int coluna, string pesquisa, int page, int rp, ref int total)
        {
            List<ProdutoDTO> listaProdutos = new List<ProdutoDTO>();
            IList<Produto> resultadoPesquisa = new List<Produto>();

            if (coluna == 0 && string.IsNullOrEmpty(pesquisa))
            {
                resultadoPesquisa = GetListaProduto(page, rp, ref total);
            }
            else
            {
                resultadoPesquisa = Pesquisar(coluna, pesquisa, page, rp, ref total);
            }

            foreach (var item in resultadoPesquisa)
            {
                ProdutoDTO prod = new ProdutoDTO();

                prod.Id = item.IdProduto;
                prod.Codigo = item.Codigo;
                prod.Categoria = item.Categoria.Categoria2.Descricao;
                prod.Subcategoria = item.Categoria.Descricao;
                prod.PrecoCusto = item.PrecoCusto;
                prod.Marca = item.Marca.Nome;
                prod.Fornecedor = item.Fornecedor.Nome;
                prod.QuantidadeEstoque = item.Estoque.Sum(e => e.Quantidade);
                prod.PrecoVenda = string.Format("{0:C}", item.PrecoCusto + (item.PrecoCusto * (decimal)item.Percentual / 100));

                listaProdutos.Add(prod);
            }
            return listaProdutos;
        }

        public List<EstoqueDTO> AdicionarEstoque(List<EstoqueDTO> listaEstoque, EstoqueDTO itemEstoque)
        {
            if (listaEstoque.Count(o => o.Tamanho == itemEstoque.Tamanho) > 0)
            {
                var itemExistente = listaEstoque.Single(o => o.Tamanho == itemEstoque.Tamanho);
                itemExistente.Quantidade += itemEstoque.Quantidade;
            }
            else
            {
                listaEstoque.Add(itemEstoque); 
            }
            return listaEstoque;
        }
    }
}
